Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Havel-Hakimi and Kleitman-Wang graph realization algorithms #202

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

InterdisciplinaryPhysicsTeam
Copy link
Member

Co-Authored-By: Pietro Monticone <[email protected]>
Co-Authored-By: Claudio Moroni <[email protected]>
@codecov
Copy link

codecov bot commented Dec 16, 2022

Codecov Report

Merging #202 (c2ca53e) into master (c4360cf) will increase coverage by 0.01%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master     #202      +/-   ##
==========================================
+ Coverage   97.43%   97.45%   +0.01%     
==========================================
  Files         113      113              
  Lines        6554     6596      +42     
==========================================
+ Hits         6386     6428      +42     
  Misses        168      168              

@simonschoelly
Copy link
Member

Somehow github send me an email, that I am mentioned in this PR - but I can't find that comment anymore. It it important that this gets merged very soon? Then I can focus more on this PR than others.

@InterdisciplinaryPhysicsTeam
Copy link
Member Author

Hi @simonschoelly ,

We're sorry for the inconvenience. We have posted a this comment here by mistake: we intended to post it in #186 (where it is right now). So we'd need #186 to be merged so the master branch of our fork is free and we may move on to the next contribution.

Comment on lines 1035 to 1052
"""
lexicographical_order_ntuple(A::NTuple{N,T}, B::NTuple{M,T}) where {N,T}

The less than (lt) function that implements lexicographical order for `NTuple`s of equal length.

See [Wikipedia](https://en.wikipedia.org/wiki/Lexicographic_order).
"""
function lexicographical_order_ntuple(A::Tuple{Vararg{<:Real}}, B::Tuple{Vararg{<:Real}})
length(A) == length(B) ||
throw(ArgumentError("The length of A must match the length of B"))
for (a, b) in zip(A, B)
if a != b
return a < b
end
end

return false
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this function? Julia already implements lexicographical orders for tuples (but it also does that for tuples of different lengths. E.g.

julia> (1, 2) < (3, 4)
true

julia> (1, 2) < (1, 2)
false

julia> (1, 2) < (1, 2, 1)
true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, we didn't think this functionality was implemented out of the box. We then removed lexicographical_order_ntuple.

Comment on lines 1006 to 1007
all(degree_sequence .>= 0) ||
throw(ArgumentError("The degree sequence must contain non-negative integers only."))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense, to just call isgraphical here? Or do you think that the overhead is too big then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, in order to maximize performance and code simplicity, we should completely separate the functionalities of isgraphical and havel_hakimi_graph. So if the user knows that the sequence is graphical and just wants the graph, she/he may use havel_hakimi_graph, while if just/also a check for graphicality is needed, then a call to isgraphical must be made.

Then I'd suggest to either:

  1. Remove all checks from havel_hakimi_graph;
  2. Add a bool kwarg check_graphicality to havel_hakimi_graph, that performs the isgraphical check before executing the algorithm (in which case we may skip the subsequent check in the loop).

Similar reasoning would apply to isdigraphical and kleitman_wang_graph.

Comment on lines 1023 to 1024
all(collect(values(vertices_degrees_dict))[1:max_degree] .> 0) ||
throw(ErrorException("The degree sequence is not graphical."))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably more efficient to do this check, when set vertices_degrees_dict[vertex] -= 1.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I inserted this check in the loop. But it may be temporary, depending on what comes out of this comment.

Comment on lines 1017 to 1019
vertices_degrees_dict = OrderedDict(
sort(collect(vertices_degrees_dict); by=last, rev=true)
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
vertices_degrees_dict = OrderedDict(
sort(collect(vertices_degrees_dict); by=last, rev=true)
)
sort!(vertices_degrees_dict, byvalues=true, rev=true)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It throws an error https://github.com/JuliaGraphs/Graphs.jl/actions/runs/3919202599/jobs/6700055795.

So we reinstated the allocating line.

@@ -989,6 +989,144 @@ function uniform_tree(n::Integer; rng::Union{Nothing,AbstractRNG}=nothing)
return prufer_decode(random_code)
end

"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if randgraphs.jl is the correct place for these functions, maybe staticgraphs.jl is a better place, as generators are not random.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We moved it to staticgraphs.jl. Thanks for the suggestion.

# Instantiate an empty simple graph
graph = SimpleGraph(length(degree_sequence))
# Create a (vertex, degree) ordered dictionary
vertices_degrees_dict = OrderedDict(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as it work correctly, we can keep it that way, but we probably could make this function much faster, by using a Vector of tuples instead. The sorting step should also be fairly easy to speed up, as after adding a vertex, the degree order is only slightly not sorted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We unfortunately don't have much time for this, but it would surely help. Would even be better if the final instantiation of a graph object was optional or put in a wrapper method, so that also other packages in the ecosystem may benefit from the full performance of the method (e.g. MutlilayerGraphs.jl's configuration model-like constructors).

Co-Authored-By: Pietro Monticone <[email protected]>
Co-Authored-By: Claudio Moroni <[email protected]>
Co-Authored-By: Pietro Monticone <[email protected]>
Co-Authored-By: Claudio Moroni <[email protected]>
Co-Authored-By: Pietro Monticone <[email protected]>
Co-Authored-By: Claudio Moroni <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants